<template>
  <div class="number-scroll">
    {{ formattedValue }}
  </div>
</template>

<script setup>
import { ref, onMounted, watch, computed } from 'vue';

const props = defineProps({
  // 起始值
  start: {
    type: Number,
    default: 0
  },
  // 目标值
  end: {
    type: Number,
    required: true
  },
  // 动画持续时间(毫秒)
  duration: {
    type: Number,
    default: 2000
  },
  // 是否自动播放
  autoplay: {
    type: Boolean,
    default: true
  },
  // 保留小数位数
  decimals: {
    type: Number,
    default: 0
  },
  // 前缀
  prefix: {
    type: String,
    default: ''
  },
  // 后缀
  suffix: {
    type: String,
    default: ''
  },
  // 千位分隔符
  separator: {
    type: String,
    default: ','
  }
});

// 当前显示的值
const currentValue = ref(props.start);
// 动画帧ID
let animationId = null;
// 动画开始时间
let startTime = null;

// 格式化显示值
const formattedValue = computed(() => {
  // 处理小数位数
  let num = Number(currentValue.value.toFixed(props.decimals));
  
  // 处理千位分隔符
  if (props.separator) {
    const parts = num.toString().split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, props.separator);
    num = parts.join('.');
  }
  
  return `${props.prefix}${num}${props.suffix}`;
});

// 动画函数
const animate = (timestamp) => {
  if (!startTime) startTime = timestamp;
  const progress = Math.min((timestamp - startTime) / props.duration, 1);
  
  // 使用缓动函数使动画更自然
  const easeProgress = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
  
  currentValue.value = props.start + (props.end - props.start) * easeProgress;
  
  if (progress < 1) {
    animationId = requestAnimationFrame(animate);
  }
};

// 开始动画
const start = () => {
  cancelAnimationFrame(animationId);
  startTime = null;
  animationId = requestAnimationFrame(animate);
};

// 暂停动画
const pause = () => {
  cancelAnimationFrame(animationId);
};

// 重置动画
const reset = () => {
  cancelAnimationFrame(animationId);
  currentValue.value = props.start;
  startTime = null;
};

// 自动播放
onMounted(() => {
  if (props.autoplay) {
    start();
  }
});

// 监听目标值变化，重新开始动画
watch(() => props.end, () => {
  if (props.autoplay) {
    start();
  }
});

// 暴露方法给父组件
defineExpose({
  start,
  pause,
  reset
});
</script>

<style scoped>
.number-scroll {
  font-variant-numeric: tabular-nums; /* 确保数字等宽对齐 */
}
</style>
